package com.github.permissiondog.cancanpbackend.service;

import com.github.permissiondog.cancanpbackend.Database;
import com.github.permissiondog.cancanpbackend.dao.ApproverDao;
import com.github.permissiondog.cancanpbackend.dao.TableChoiceDao;
import com.github.permissiondog.cancanpbackend.dao.TableQuestionDao;
import com.github.permissiondog.cancanpbackend.dao.TableTemplateDao;
import com.github.permissiondog.cancanpbackend.model.*;
import lombok.Getter;

import java.time.LocalDateTime;
import java.util.List;

public class TemplateService {
    private TemplateService() {

    }
    @Getter
    private static final TemplateService instance = new TemplateService();

    public TableTemplate createTemplate(String tableName, int creatorId) {
        var t = new TableTemplate();
        t.setTableName(tableName);
        t.setCreationTime(LocalDateTime.now());
        t.setCreatorId(creatorId);
        t.setDescription("");
        try (var session = Database.getInstance().openSession()) {
            var templateDao = session.getMapper(TableTemplateDao.class);
            templateDao.insertTemplate(t);
            return t;
        }
    }

    public void modifyTemplate(TableTemplate template) {
        try (var session = Database.getInstance().openSession()) {
            var templateDao = session.getMapper(TableTemplateDao.class);
            templateDao.updateTemplate(template);
        }
    }

    public TableTemplate getTemplateById(int id) {
        try (var session = Database.getInstance().openSession()) {
            var templateDao = session.getMapper(TableTemplateDao.class);
            return templateDao.getTemplateById(id);
        }
    }

    public List<TableTemplate> getTemplates() {
        try (var session = Database.getInstance().openSession()) {
            var templateDao = session.getMapper(TableTemplateDao.class);
            return templateDao.getTemplates();
        }
    }

    public boolean deleteTemplate(int id) {
        try (var session = Database.getInstance().openSession()) {
            var templateDao = session.getMapper(TableTemplateDao.class);
            return templateDao.deleteTemplate(id) == 1;
        }
    }

    public TableQuestion createQuestion(int templateId, String title, QuestionType type) {
        var q = new TableQuestion();
        q.setTemplateId(templateId);
        q.setTitle(title);
        q.setType(type);
        try (var session = Database.getInstance().openSession()) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            questionDao.insertQuestion(q);
            return getQuestionById(q.getId());
        }
    }

    public TableQuestion getQuestionById(int id) {
        try (var session = Database.getInstance().openSession()) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            return questionDao.getQuestionById(id);
        }
    }

    public List<TableQuestion> getQuestionsByTemplateId(int templateId) {
        try (var session = Database.getInstance().openSession()) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            return questionDao.getQuestionByTemplateId(templateId);
        }
    }

    public boolean deleteQuestion(int id) {
        try (var session = Database.getInstance().openSession(false)) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            var question = questionDao.getQuestionById(id);
            if (question == null) {
                return false;
            }
            var ok = questionDao.deleteQuestion(id) == 1;
            if (!ok) {
                return false;
            }
            questionDao.getQuestionsGreaterThan(question.getTemplateId(), question.getQuestionNumber()).forEach(q -> {
                q.setQuestionNumber(q.getQuestionNumber() - 1);
                questionDao.updateQuestion(q);
            });

            session.commit();
            return true;
        }
    }

    public void swapQuestion(int id1, int id2) {
        try (var session = Database.getInstance().openSession(false)) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            var q1 = questionDao.getQuestionById(id1);
            var q2 = questionDao.getQuestionById(id2);
            if (q1.getTemplateId() != q2.getTemplateId()) {
                throw new RuntimeException("模板 ID 不一致");
            }

            var temp1 = q1.getQuestionNumber();
            var temp2 = q2.getQuestionNumber();
            q1.setQuestionNumber(-1);
            questionDao.updateQuestion(q1);
            q2.setQuestionNumber(temp1);
            questionDao.updateQuestion(q2);
            q1.setQuestionNumber(temp2);
            questionDao.updateQuestion(q1);
            session.commit();
        }
    }

    public void modifyQuestion(TableQuestion question) {
        try (var session = Database.getInstance().openSession(false)) {
            var questionDao = session.getMapper(TableQuestionDao.class);
            var oldQuestion = questionDao.getQuestionById(question.getId());
            if (oldQuestion.getType().isChoice() && !question.getType().isChoice()) {
                var choiceDao = session.getMapper(TableChoiceDao.class);
                choiceDao.deleteChoices(question.getId());
            }
            questionDao.updateQuestion(question);
            session.commit();
        }
    }

    public void setChoice(int questionId, List<String> names) {
        try (var session = Database.getInstance().openSession(false)) {
            var choiceDao = session.getMapper(TableChoiceDao.class);
            choiceDao.deleteChoices(questionId);
            for (int i = 0; i < names.size(); i++) {
                var choice = new TableChoice();
                choice.setQuestionId(questionId);
                choice.setName(names.get(i));
                choice.setChoiceNumber(i+1);
                choiceDao.insertChoice(choice);
            }
            session.commit();
        }
    }

    public List<TableChoice> getChoices(int questionId) {
        try (var session = Database.getInstance().openSession()) {
            var choiceDao = session.getMapper(TableChoiceDao.class);
            return choiceDao.getChoices(questionId);
        }
    }

    public Approver addApprover(int templateId, int approverId) {
        var a = new Approver();
        a.setTemplateId(templateId);
        a.setApproverId(approverId);
        try (var session = Database.getInstance().openSession()) {
            var approverDao = session.getMapper(ApproverDao.class);
            approverDao.insertApprover(a);
            return getApprover(templateId, approverId);
        }
    }

    public List<Approver> getApprovers(int templateId) {
        try (var session = Database.getInstance().openSession()) {
            var approverDao = session.getMapper(ApproverDao.class);
            return approverDao.getApprovers(templateId);
        }
    }

    public Approver getApprover(int templateId, int approverId) {
        try (var session = Database.getInstance().openSession()) {
            var approverDao = session.getMapper(ApproverDao.class);
            return approverDao.getApprover(templateId, approverId);
        }
    }
    public boolean deleteApprover(int templateId, int approverId) {
        try (var session = Database.getInstance().openSession(false)) {
            var approverDao = session.getMapper(ApproverDao.class);
            var approver = approverDao.getApprover(templateId, approverId);
            if (approver == null) {
                return false;
            }
            var ok = approverDao.deleteApprover(templateId, approverId) == 1;
            if (!ok) {
                return false;
            }
            approverDao.getApproversGreaterThan(templateId, approver.getNumber()).forEach(a -> {
                a.setNumber(a.getNumber() - 1);
                approverDao.updateApprover(a);
            });

            session.commit();
            return true;
        }
    }

    public void swapApprover(int templateId, int approverId1, int approverId2) {
        try (var session = Database.getInstance().openSession(false)) {
            var approverDao = session.getMapper(ApproverDao.class);
            var a1 = approverDao.getApprover(templateId, approverId1);
            var a2 = approverDao.getApprover(templateId, approverId2);

            var temp1 = a1.getNumber();
            var temp2 = a2.getNumber();
            a1.setNumber(-1);
            approverDao.updateApprover(a1);
            a2.setNumber(temp1);
            approverDao.updateApprover(a2);
            a1.setNumber(temp2);
            approverDao.updateApprover(a1);
            session.commit();
        }
    }
}
